package handler

import (
	"bytes"
	"fmt"
	"gitee.com/godY/daminghu-cli/cfg"
	"gitee.com/godY/daminghu-cli/common"
	"github.com/astaxie/beego/logs"
	"github.com/mholt/archiver"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"regexp"
)

var (
	keyWordsMap map[string]string
)

func init() {
	keyWordsMap = make(map[string]string, 0)
	keyWordsMap["break"] = "ybreak"
	keyWordsMap["default"] = "ydefault"
	keyWordsMap["func"] = "yfunc"
	keyWordsMap["interface"] = "yinterface"
	keyWordsMap["select"] = "yselect"
	keyWordsMap["case"] = "ycase"
	keyWordsMap["chan"] = "ychan"
	keyWordsMap["const"] = "yconst"
	keyWordsMap["continue"] = "ycontinue"
	keyWordsMap["defer"] = "ydefer"
	keyWordsMap["go"] = "ygo"
	keyWordsMap["map"] = "ymap"
	keyWordsMap["struct"] = "ystruct"
	keyWordsMap["else"] = "yelse"
	keyWordsMap["goto"] = "ygoto"
	keyWordsMap["package"] = "ypackage"
	keyWordsMap["switch"] = "yswitch"
	keyWordsMap["fallthrough"] = "yfallthrough"
	keyWordsMap["if"] = "yif"
	keyWordsMap["range"] = "yrange"
	keyWordsMap["type"] = "ytype"
	keyWordsMap["for"] = "yfor"
	keyWordsMap["import"] = "yimport"
	keyWordsMap["return"] = "yreturn"
	keyWordsMap["var"] = "yvar"
}

type HandlerOneTableFunc func(table *common.Table, columns []*common.Column)
type HandlerTablesFunc func(table []*common.Table)

type BaseInfo struct {
	Auth        string
	ProjectUri  string
	ProjectName string
	PreUrl      string
	Port        string
	MySqlConn   string

	Package          string
	FirstColumnName  string
	SecondColumnName string
	TableNameLow     string
	TableNameUpper   string

	Table   *common.Table
	Tables  []*common.Table
	Columns []*common.Column
}

func (b *BaseInfo) SetUp() {
	b.Auth = common.CreateAuthor()
	b.ProjectUri = cfg.Cfg.GetFullProjectUri()
	b.PreUrl = cfg.Cfg.PreUrl
	b.Port = cfg.Cfg.Port
	b.ProjectName = cfg.Cfg.ProjectName
	b.MySqlConn = cfg.Cfg.GetMySqlConn()
}

func init() {

	MyFunc = map[string]interface{}{}
	MyFunc["Low"] = Low
	MyFunc["Upper"] = Upper
	MyFunc["IsLast"] = IsLast
	MyFunc["IsLastTable"] = IsLastTable
	MyFunc["ReplaceUnderLine"] = ReplaceUnderLine
	MyFunc["ReplaceUnderLineLow"] = ReplaceUnderLineLow
	MyFunc["ToPropName"] = ToPropName
	MyFunc["ConvertKeyWord"] = ConvertKeyWord
	MyFunc["ConvertComment"] = ConvertComment
}

var MyFunc map[string]interface{}

func Low(str string) string {
	return strings.ToLower(str)
}

func Upper(str string) string {
	return strings.ToUpper(str)
}

func ReplaceUnderLine(str string) string {
	return strings.Replace(str, "_", "-", -1)
}

func ReplaceUnderLineLow(str string) string {
	return Low(ReplaceUnderLine(str))
}

func IsLast(index int, array []*common.Column) string {
	if index != len(array)-1 {
		return ","
	} else {
		return ""
	}
}

func IsLastTable(index int, array []*common.Table) string {
	if index != len(array)-1 {
		return ","
	} else {
		return ""
	}
}

func ToPropName(str string) string {
	return "{{ props.row." + strings.ToLower(str) + "}}"
}

func ConvertKeyWord(str string) string {
	if v, ok := keyWordsMap[strings.ToLower(str)]; ok {
		return v
	}
	return strings.ToLower(str)
}

func ConvertComment(str string) string {
	//logs.Debug("old", str)
	reg := regexp.MustCompile(`[\f\t\n\r\v\123\x7F\x{10FFFF}\\\^\$\.\*\+\?\{\}\(\)\[\]\|]`)
	str = reg.ReplaceAllString(str, "")
	str = strings.Replace(str, "\uFEFF", "", -1)
	str = strings.Replace(str, " ", "", -1)
	str = strings.Replace(str, "\"", "", -1)
	str = strings.Replace(str, "'", "", -1)
	//logs.Debug("new", str)
	return strings.ToLower(str)
}

//
//func CreateDistFile(cfgfilename string, cfgfilepath string, distfilename string, distfilepath string, data interface{}) {
//
//	tmpl, err := template.New(cfgfilename).Funcs(MyFunc).ParseFiles(cfgfilepath + cfgfilename)
//	if err != nil {
//		panic(err)
//	}
//	file, err := os.Create(distfilepath + distfilename)
//	if err != nil {
//		panic(err)
//	}
//	err = tmpl.Execute(file, &data)
//	if err != nil {
//		panic(err)
//	}
//}

func DownloadFile(url string, savefilepath string) error {
	logs.Debug("DownloadFile", url, savefilepath)
	resp, err := http.Get(url)

	if err != nil {
		// handle error
		panic(err)
	}
	//logs.Debug(resp.Status, resp.StatusCode)
	defer resp.Body.Close()

	//contentType := resp.Header["Content-Type"]
	//isZip := false
	//for _, v := range contentType {
	//	if v == "application/zip" {
	//		isZip = true
	//		break
	//	}
	//}
	//if isZip {
	//	fmt.Println(resp.Header["Content-Type"])
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(savefilepath, body, os.ModePerm)

	if err != nil {
		panic(err)
	}
	//}
	return err
}

func Unzip(source string, dest string) {
	logs.Debug("Unzip", source, dest)
	err := archiver.Unarchive(source, dest)
	if err != nil {
		panic(err)
	}
}

func PostJson(data string, url string) []byte {

	resp, err := http.Post(url,
		"application/json",
		strings.NewReader(data))
	if err != nil {
		fmt.Println(err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		//panic(err)
	}

	fmt.Println(string(body))
	return body
}

func PostFiles(uri string, params map[string]string, filenames []string, filepaths []string) (*http.Response, error) {

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	for index, fp := range filepaths {
		file, err := os.Open(fp)
		if err != nil {
			return nil, err
		}
		defer file.Close()

		part, err := writer.CreateFormFile(filenames[index], filepath.Base(fp))
		if err != nil {
			return nil, err
		}
		_, err = io.Copy(part, file)
	}

	for key, val := range params {
		_ = writer.WriteField(key, val)
	}

	err := writer.Close()
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", uri, body)
	req.Header.Set("Content-Type", writer.FormDataContentType())

	return http.DefaultClient.Do(req)
}

//func PostFile(filename string, target_url string) (*http.Response, error) {
//	body_buf := bytes.NewBufferString("")
//	body_writer := multipart.NewWriter(body_buf)
//
//	// use the body_writer to write the Part headers to the buffer
//	_, err := body_writer.CreateFormFile("data", filename)
//	if err != nil {
//		fmt.Println("error writing to buffer")
//		return nil, err
//	}
//
//	// the file data will be the second part of the body
//	fh, err := os.Open(filename)
//	if err != nil {
//		fmt.Println("error opening file")
//		return nil, err
//	}
//	// need to know the boundary to properly close the part myself.
//	boundary := body_writer.Boundary()
//	//close_string := fmt.Sprintf("\r\n--%s--\r\n", boundary)
//	close_buf := bytes.NewBufferString(fmt.Sprintf("\r\n--%s--\r\n", boundary))
//
//	// use multi-reader to defer the reading of the file data until
//	// writing to the socket buffer.
//	request_reader := io.MultiReader(body_buf, fh, close_buf)
//	fi, err := fh.Stat()
//	if err != nil {
//		fmt.Printf("Error Stating file: %s", filename)
//		return nil, err
//	}
//	req, err := http.NewRequest("POST", target_url, request_reader)
//	if err != nil {
//		return nil, err
//	}
//
//	// Set headers for multipart, and Content Length
//	req.Header.Add("Content-Type", "multipart/form-data; boundary="+boundary)
//	req.ContentLength = fi.Size() + int64(body_buf.Len()) + int64(close_buf.Len())
//
//	return http.DefaultClient.Do(req)
//}
